/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools test utils
 */

#ifndef HMFS_TEST_UTILS_H
#define HMFS_TEST_UTILS_H

#include <vector>
#include <assert.h>
#include <inttypes.h>
#include <map>
#include <string>
#include <sys/stat.h>

#include "hmfs_common.h"
#include "hmfs_fs.h"

namespace OHOS {
namespace Hmfs {
const std::string F2FS_RESIZE_BINARY_PATH = "/system/bin/resize.f2fs";
const std::string HMFS_RESIZE_BINARY_PATH = "/system/bin/resize.hmfs";
const std::string F2FS_MKFS_BINARY_PATH = "/system/bin/mkfs.f2fs";
const std::string HMFS_MKFS_BINARY_PATH = "/system/bin/mkfs.hmfs";
const std::string FSCK_BINARY_PATH = "/system/bin/fsck.f2fs";
const std::string F2FS_DEVICE = "/data/local/f2fsTest";
const std::string HMFS_DEVICE = "/data/local/hmfsTest";
const std::string HMFS_TYPE = "hmfs";
const std::string F2FS_TYPE = "f2fs";

constexpr int32_t NEED_SAFE_RESIZE_FLAG = 1;
constexpr int32_t OUT_OF_RANGE = 2;
constexpr int32_t VALID = 0;
constexpr int32_t MORE_SEGMENT_NEEDED = 3;

constexpr int32_t PREAD_BUFFER_SIZE = 4096;
constexpr int32_t SUPER_BLOCK_OFFSET = 1024;
constexpr uint8_t MAX_DEVICE_COUNTS = 8;
constexpr uint16_t MAX_VOLUME_LENGTH = 512;
constexpr int32_t MSEC_TO_NSEC = 1000000;
constexpr int32_t SEC_TO_MSEC = 1000;
constexpr int32_t TEST_FILE_SIZE = 100 * 1024 * 1024;
const std::string HMFS_DEVICE_PATH_LIST[MAX_DEVICE_COUNTS] = {
    "/data/local/hmfsTest0",
    "/data/local/hmfsTest1",
    "/data/local/hmfsTest2",
    "/data/local/hmfsTest3",
    "/data/local/hmfsTest4",
    "/data/local/hmfsTest5",
    "/data/local/hmfsTest6",
    "/data/local/hmfsTest7"
};

const std::string F2FS_DEVICE_PATH_LIST[MAX_DEVICE_COUNTS] = {
    "/data/local/f2fsTest0",
    "/data/local/f2fsTest1",
    "/data/local/f2fsTest2",
    "/data/local/f2fsTest3",
    "/data/local/f2fsTest4",
    "/data/local/f2fsTest5",
    "/data/local/f2fsTest6",
    "/data/local/f2fsTest7"
};

const std::string HMFS_PARAMETER_LIST[] = {
    "-a", "-d", "-e", "-E", "-l", "-o", "-O", "-C", "-R", "-s", "-t", "-T", "-w", "-z"
};

const std::string HMFS_RESIZE_PARAMETER_LIST[] = {
    "-d", "-C", "-O", "-o", "-t",
};

enum HmfsCode {
    SUCCESSED       = 0,
    FAILED          = 1,
    // other reasons, such as empty file name, failed to open the file, failed to format the file
    ERROR_OTHER     = 2 
};

enum SuperBlockCode {
    SUCCESSED_SB = 0,
    ERROR_SB_UNKNOWN,
    ERROR_LOG_SECTOR_SIZE,
    ERROR_LOG_SECTORS_PER_BLK,
    ERROR_LOG_BLOCK_SIZE,
    ERROR_LOG_BLKS_PER_SEG,
    ERROR_SEGS_PER_SECTION,
    ERROR_SECTIONS_PER_ZONE,
    ERROR_SB_CHECKSUM_OFFSET,
    ERROR_BLOCK_COUNT,
    ERROR_SECTION_COUNT,
    ERROR_SEGMENT_COUNT,
    ERROR_SEGMENT_COUNT_IN_CP,
    ERROR_SEGMENT_COUNT_IN_SIT,
    ERROR_SEGMENT_COUNT_IN_NAT,
    ERROR_SEGMENT_COUNT_IN_SSA,
    ERROR_SEGMENT_COUNT_IN_MAIN,
    ERROR_SEGMENT0_BLKID,
    ERROR_CP_BLKID,
    ERROR_SIT_BLKID,
    ERROR_NAT_BLKID,
    ERROR_SSA_BLKID,
    ERROR_MAIN_BLKID,
    ERROR_ROOT_INODE_ID,
    ERROR_NODE_INODE_ID,
    ERROR_META_INODE_ID,
    ERROR_EXTENSION_COUNT,
    ERROR_VOLUME_NAME,
    ERROR_EXTENSION_LIST,
    ERROR_CP_PAY_LOAD,
    ERROR_FEATURES,
    ERROR_ENCRYPTION_LEVEL,
    ERROR_HOT_EXTENSION_COUNT,
    ERROR_S_ENCODING,
    ERROR_S_ENCODING_FLAGS
};

enum CheckPointCode {
    SUCCESSED_CP = 0,
    ERROR_CP_UNKNOWN,
    ERROR_USER_BLOCK_COUNT,
    ERROR_VALID_BLOCK_COUNT,
    ERROR_RSVD_SEGMENT_COUNT,
    ERROR_OVERPROV_SEGMENT_COUNT,
    ERROR_FREE_SEGMENT_COUNT,
    ERROR_CUR_NODE_SEG_NO,
    ERROR_CUR_NODE_BLK_OFFSET,
    ERROR_CUR_DATA_SEG_NO,
    ERROR_CUR_DATA_BLK_OFFSET,
    ERROR_ALLOC_TYPE,
    ERROR_CP_FLAGS,
    ERROR_CP_PACK_BLOCK_COUNT,
    ERROR_CP_PACK_START_SUM,
    ERROR_VALID_NODE_COUNT,
    ERROR_VALID_INODE_COUNT,
    ERROR_NEXT_FREE_NODE_ID,
    ERROR_SIT_VERSION_BITMAP_SIZE,
    ERROR_NAT_VERSION_BITMAP_SIZE,
    ERROR_CP_CHECKSUM_OFFSET
};

enum NodeDataCode {
    SUCCESSED_ND = 0,
    ERROR_NODE_UNKNOWN,
    ERROR_NODE_MODE,
    ERROR_NODE_ADVISE,
    ERROR_NODE_UID,
    ERROR_NODE_GID,
    ERROR_NODE_LINKS,
    ERROR_NODE_SIZE,
    ERROR_NODE_BLOCKS,
    ERROR_NODE_ATIME,
    ERROR_NODE_ATIME_NSEC,
    ERROR_NODE_CTIME,
    ERROR_NODE_CTIME_NSEC,
    ERROR_NODE_MTIME,
    ERROR_NODE_MTIME_NSEC,
    ERROR_NODE_GENRATION,
    ERROR_NODE_CURRENT_DEPTH,
    ERROR_NODE_XATTR_NID,
    ERROR_NODE_FLAGS,
    ERROR_NODE_INLINE,
    ERROR_NODE_PINO,
    ERROR_NODE_DIR_LEVEL,
    ERROR_NODE_EXT,
    ERROR_NODE_ADDR,
    ERROR_NODE_NID,
    ERROR_NODE_EXTRA_ISIZE,
    ERROR_NODE_INLINE_XATTR_SIZE,
    ERROR_NODE_PROJID,
    ERROR_NODE_COMPRESSION
};

HmfsCode WriteFile(const std::string &fileName);
std::string ReadFile(const std::string &fileName);
HmfsCode GetFileStat(const std::string &fileName, struct stat *statBuf);
HmfsCode CheckDataIsZero(const std::string &fileName);
HmfsCode FAllocateFile(const std::string &fileName);
void ClearFile(const std::string &fileName);
unsigned long long GetFileSize(const std::string &fileName);
void PrintParameters(const std::vector<std::string> &params);

void DataDuplicatorDevice(const std::string &devicePath);
int32_t ExecutableCmd(const char *path, char *const argv[]);
int32_t ExecMkfsBinary(const std::string &fsType, const std::string &devPath,
    const std::vector<std::string> &params = std::vector<std::string>());
void ExecutableDdCmd(const std::string &device, int32_t count);
int32_t ExecutableCmdWithOutput(std::vector<std::string> &params, std::string &outputFile);
int32_t ExecutableCmdWithOutput(std::vector<std::string> &params, std::string &outputFile, uint64_t &runTime);
int32_t ExecMkfsBinary(const std::string &fsType, const std::string &devPath, const std::vector<std::string> &params,
    uint64_t &runTime);
int32_t ExecutableCmd(const char *path, char *const argv[], uint64_t &runTime);

int32_t ExecFsckWithOutput(std::string &device, std::string &outputFile);
bool ExecFsckBinaryAndCheck(const std::string &devPath);
int32_t ExecResizeBinary(std::string tool, std::vector<std::string> &params, std::string device);
int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector<std::string> &params,
    std::string device, std::string &outputFile);
int32_t ExecResizeBinary(std::string tool, std::vector<std::string> &params, std::string device, uint64_t &runTime);
int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector<std::string> &params,
    std::string device, std::string &outputFile, uint64_t &runTime);
int32_t RemoveFile(std::string &file);
std::unordered_map<std::string, uint64_t> ParseInodeInfo(const std::string &outputFile);
void GetNodeDataFromMap(std::unique_ptr<NodeData> &nodeData, int16_t &addrIndex,
    const std::unordered_map<std::string, uint64_t> &inodeInfo);

// Dump data
void GetSuperBlock(const std::string &devPath, std::unique_ptr<SuperBlockData> &superBlock);
void GetCheckPoint(const std::string &devPath, std::unique_ptr<CheckPointData> &checkPoint);
void GetInodeInfo(const std::string &devPath, std::unique_ptr<NodeData> &nodeData,
    int16_t &addrIndex, const uint32_t inode);
void PrintRawSuperBlockInfo(const std::unique_ptr<SuperBlockData> &superBlock);
void PrintCPInfo(const std::unique_ptr<CheckPointData> &checkPoint);
void PrintInodeInfo(uint32_t features, const std::unique_ptr<NodeData> &node,
    const int16_t addrIndex, const uint32_t iNodeNum);
void PrintSuperBlockAndCheckPointData(const std::string &device);

std::string ConfirmDevicePath(const std::vector<std::string> &params, const bool changePath = true);
std::string FindSpecifyStr(const std::vector<std::string> &vecStr, const std::string &item);
bool ContainSubStr(const std::string &parameterValue, const std::string &subStr);

bool CheckFeatures(const uint32_t features, const std::string &featureNameList);
bool CheckParametersVaild(const std::vector<std::string> &params, std::map<std::string, std::string> &parameterMap);
int32_t CheckResizeParameters(std::string &device, const std::vector<std::string> &params,
    const uint32_t deviceSectorCount, std::map<std::string, std::string> &parameterMap);
bool CheckMkfsHmfsResult(const std::map<std::string, std::string> &parameterMap,
    const std::unique_ptr<CheckPointData> &checkPoint, const std::unique_ptr<SuperBlockData> &superBlock,
    const std::unique_ptr<NodeData> &nodeData);
bool CheckResizeHmfsResult(const std::map<std::string, std::string> &parameterMap,
    const std::unique_ptr<CheckPointData> &checkPoint, const std::unique_ptr<SuperBlockData> &superBlock,
    const std::string &output);
bool PrintFsckErrorMsg(const std::string &outputFile, const std::string &devicePath);
bool CheckSafeResize(const std::map<std::string, std::string> &parameterMap, const std::unique_ptr<SuperBlockData> &superBlock);
SuperBlockCode CompareSuperBlock(const std::unique_ptr<SuperBlockData> &f2SB, const std::unique_ptr<SuperBlockData> &hmSB);
CheckPointCode CompareCheckPoint(const std::unique_ptr<CheckPointData> &f2CP, const std::unique_ptr<CheckPointData> &hmCP);
NodeDataCode CompareNodeData(const std::unique_ptr<NodeData> &f2CP, const std::unique_ptr<NodeData> &hmCP,
    const int16_t addrIndex, const bool compTime = false);

// Generate random
std::vector<std::string> GenerateParams(bool isResizeTool = true);
void GenerateMkfsParams(std::vector<std::string> &params);
void GenerateMkfsParamsEnd(std::vector<std::string> &params);

void ReplaceDevicePaths(std::vector<std::string> &params);

std::string GenerateFeatures(bool isResizeTool = true);
std::string GenerateRandomString(const size_t length);
int32_t GenerateRandomInt32(const int32_t startNum = -10);

uint64_t GetCurrentTime();
bool CompareRunTime(uint64_t f2fsTime, uint64_t hmfsTime);
} // namespace Hmfs
} // namespace OHOS
#endif // HMFS_TEST_UTILS_H